﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Orange.Lib.Effective
{
    using Effective.DynamicUse;

    namespace TypeCast
    {
        public abstract class Shape
        {
            public int x { get; set; }
            public int y { get; set; }
            public int r { get; set; }
        }

        public class Circle : Shape { }

        public class Ellipse : Shape
        {
            /* About user-define explicit cast
            1) What is that? 
               eg: Circle c = new Circle();
                    Ellipse e = (Ellipse) c;
               error:
                Ellipse e = c as Ellipse; //as is diff with explicit cast!
             
            2) What should be cared about?
                1.It's compile-time not runtime.
                2.Always use 'is' or 'as' to cast. (Demo2)
                3.Not supported with base-derived relationship.
                4.Not supported by Cast<T>() Method.
             */

            static public explicit operator Ellipse(Circle c)
            {
                Debug.WriteLine("Use user-defined cast (explicit)");

                return new Ellipse()
                {
                    r = c.r,
                    x = c.x,
                    y = c.y
                };
            }

            public override string ToString()
            {
                return string.Format("Ellipse as r: {0}, x: {1}, y: {2}",
                    this.r, this.x, this.y);
            }
        }

        public class Display
        {
            public static void Demo()
            {
                //instance a List of Circle
                List<Circle> circles = new List<Circle> { };
                List<Ellipse> ellipses = null;
                List<Shape> shapes = null;
                for (int i = 0; i < 3; i++)
                {
                    circles.Add
                    (
                        new Circle { r = i, x = i, y = i }
                    );
                }
                try
                {


                    //Cast<T> is lazy-load method.
                    shapes = circles.Cast<Shape>().ToList();
                    ellipses = circles.Cast<Ellipse>().ToList();
                }
                catch
                {
                    Console.WriteLine("Cast<T> not support user-defined cast (implicit or explicit)");

                    //please refer to DynamicUse.cs file.
                    ellipses = circles.Convert<Ellipse>().ToList();
                }
                finally
                {
                    if (ellipses != null && ellipses.Count > 0)
                    {
                        Console.WriteLine("Get Ellipse: ");
                        ellipses.ForEach(e => Console.WriteLine(e.ToString()));
                    }
                }
            }


            public static void Demo2()
            {
                object o = new Circle();
                Debug.WriteLine("object o's runtime type: " + o.GetType().Name);
                Ellipse e = null;
                try
                {
                    //invalid cast
                    e = (Ellipse)o;
                }
                catch
                {
                    //Version 1:
                    Circle c = o as Circle;
                    if (c != null)
                        e = (Ellipse)c;

                    //Version 2:
                    if (o is Circle)
                    {
                        c = (Circle)o;
                        e = (Ellipse)c;
                    }
                }
            }
        }
    }
}
